package top.pin90;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import top.pin90.config.HolidayConfig2022;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.List;

public class GenerateCalendar {
    private HolidayConfig holidayConfig;
    private JSONObject node;

    public GenerateCalendar(HolidayConfig holidayConfig) {
        this.holidayConfig = holidayConfig;
    }

    public void generate() throws IOException {
        // 主内容
        String fileNameFormat = "%s-%s-rest.json";
        Path jsonPath = Paths.get("data/" + String.format(fileNameFormat, holidayConfig.getYear(), holidayConfig.getRestMode()));
        BufferedWriter bufferedWriter = Files.newBufferedWriter(jsonPath, StandardCharsets.UTF_8);
        JSON.writeJSONString(bufferedWriter, generateJSONObject(), SerializerFeature.PrettyFormat);
        System.out.println("jsonPath: " + jsonPath);
        // 版本文件
        String versionFileNameFormat = "%s-%s-version";
        Path versionPath = Paths.get("data/" + String.format(versionFileNameFormat, holidayConfig.getYear(), holidayConfig.getRestMode()));
        Files.write(versionPath, (holidayConfig.getVersion() + "").getBytes(StandardCharsets.UTF_8));
        System.out.println("versionPath: " + versionPath);
    }

    public JSONObject generateJSONObject() {

        initNode();

        commonProperty();

        normalDay();

        handBusyAndRestDay();

        return node;
    }

    public void initNode() {
        JSONObject node = new JSONObject();

        JSONObject index = new JSONObject();
        JSONArray dates = new JSONArray(366);
        JSONObject property = new JSONObject();
        node.put("index", index);
        node.put("dates", dates);
        node.put("property", property);

        this.node = node;
    }

    public void commonProperty() {
        JSONObject property = node.getJSONObject("property");
        property.put("version", holidayConfig.getVersion());
        property.put("year", holidayConfig.getYear());
        property.put("desc", holidayConfig.getDesc());
    }

    public void normalDay() {
        JSONObject index = node.getJSONObject("index");
        JSONArray dates = node.getJSONArray("dates");


        int i = 0;
        for (int month = 1; month <= 12; month++) {
            LocalDate md = LocalDate.of(holidayConfig.getYear(), month, 1);
            LocalDate lastDayOfMonth = md.with(TemporalAdjusters.lastDayOfMonth());
            int days = lastDayOfMonth.getDayOfMonth();
            for (int day = 1; day <= days; day++) {
                LocalDate dayDate = LocalDate.of(holidayConfig.getYear(), month, day);
                index.put(indexKey(month, day), i);
                JSONObject date = new JSONObject();
                date.put("index", i++);
                date.put("month", month);
                date.put("day", day);
                int dayOfWeek = dayDate.getDayOfWeek().getValue();
                date.put("dayOfWeek", dayOfWeek);

                int rest = 0;
                if (dayOfWeek == 6 || dayOfWeek == 7) {
                    rest = 1;
                }

                date.put("rest", rest);
                dates.add(date);
            }
        }
    }

    public void handBusyAndRestDay() {
        JSONObject index = node.getJSONObject("index");
        JSONArray dates = node.getJSONArray("dates");

        List<DayRange> busyDay = holidayConfig.getBusyDay();
        for (DayRange dayRange : busyDay) {
            setRestRangeValue(index, dates, dayRange, 0);
        }

        List<DayRange> restDay = holidayConfig.getRestDay();
        for (DayRange dayRange : restDay) {
            setRestRangeValue(index, dates, dayRange, 1);
        }
    }

    public void setRestRangeValue(JSONObject index, JSONArray dates, DayRange dayRange, Object value) {
        LocalDate start = dayRange.startDate(holidayConfig.getYear());
        LocalDate end = dayRange.endDate(holidayConfig.getYear());

        while (start.compareTo(end) <= 0) {
            String indexKey = indexKey(start.getMonthValue(), start.getDayOfMonth());
            Integer i = index.getInteger(indexKey);
            JSONObject date = dates.getJSONObject(i);
            date.put("rest", value);
            date.put("restDesc", dayRange.getDesc());
            start = start.plusDays(1);
        }
    }

    public String indexKey(int month, int day) {
        return String.format("%02d", month) + String.format("%02d", day);
    }

    public HolidayConfig getHolidayConfig() {
        return holidayConfig;
    }

    public void setHolidayConfig(HolidayConfig holidayConfig) {
        this.holidayConfig = holidayConfig;
    }
}
